<!-- build time:Tue Dec 17 2019 19:26:43 GMT+0800 (GMT+08:00) --><!doctype html><html class="theme-next mist" lang="zh-Hans"><head><meta name="generator" content="Hexo 3.8.0"><meta name="google-site-verification" content="7Tau9WyVgxnsEY9oYedu9g0U6_8akOX3wiKbaYcrg9A"><meta name="baidu-site-verification" content="EVwLiaxdxX"><link href="/css/xps13.css" rel="stylesheet" type="text/css"><link href="/css/message.css" rel="stylesheet" type="text/css"><script type="text/javascript" src="/js/jquery-1.11.3.min.js"></script><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1"><meta http-equiv="Cache-Control" content="no-transform"><meta http-equiv="Cache-Control" content="no-siteapp"><link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css"><link href="/css/main.css?v=5.1.1" rel="stylesheet" type="text/css"><meta name="keywords" content="Vue,"><link rel="alternate" href="/atom.xml" title="MrBird" type="application/atom+xml"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.1.1"><meta name="description" content="Vue (读音 /vjuː/，类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是，Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层，不仅易于上手，还便于与第三方库或既有项目整合。另一方面，当与现代化的工具链以及各种支持类库结合使用时，Vue 也完全能够为复杂的单页应用提供驱动。本篇记录Vue学习过程，用于心得备忘，对外可读性差🙃，学习Vue还是以官方"><meta name="keywords" content="Vue"><meta property="og:type" content="article"><meta property="og:title" content="Vue入门学习"><meta property="og:url" content="http://mrbird.cc/Vue-Learn-Note.html"><meta property="og:site_name" content="MrBird"><meta property="og:description" content="Vue (读音 /vjuː/，类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是，Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层，不仅易于上手，还便于与第三方库或既有项目整合。另一方面，当与现代化的工具链以及各种支持类库结合使用时，Vue 也完全能够为复杂的单页应用提供驱动。本篇记录Vue学习过程，用于心得备忘，对外可读性差🙃，学习Vue还是以官方"><meta property="og:locale" content="zh-Hans"><meta property="og:image" content="http://mrbird.cc/img/lifecycle.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181127223411.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181127224756.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181127225929.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181127231739.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181203214211.png"><meta property="og:image" content="http://mrbird.cc/img/components.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181207221803.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181207221947.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181207222107.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181207224554.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181208110210.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181208113429.png"><meta property="og:image" content="http://mrbird.cc/img/vuex.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181215211617.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181213110050.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181213104836.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181213105043.png"><meta property="og:image" content="http://mrbird.cc/img/QQ图片20181213112112.png"><meta property="og:image" content="http://mrbird.cc/img/QQ截图20181213112523.png"><meta property="og:image" content="http://mrbird.cc/img/localstorage插件编写方法.png"><meta property="og:updated_time" content="2019-10-28T12:14:46.293Z"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Vue入门学习"><meta name="twitter:description" content="Vue (读音 /vjuː/，类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是，Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层，不仅易于上手，还便于与第三方库或既有项目整合。另一方面，当与现代化的工具链以及各种支持类库结合使用时，Vue 也完全能够为复杂的单页应用提供驱动。本篇记录Vue学习过程，用于心得备忘，对外可读性差🙃，学习Vue还是以官方"><meta name="twitter:image" content="http://mrbird.cc/img/lifecycle.png"><script type="text/javascript" id="hexo.configurations">var NexT=window.NexT||{},CONFIG={root:"/",scheme:"Mist",sidebar:{position:"left",display:"always",offset:12,offset_float:0,b2t:!1,scrollpercent:!1},fancybox:!1,motion:!1}</script><title>Vue入门学习 | MrBird</title></head><body ondragstart="return!1" class="animsition" lang="zh-Hans" style="overflow-x:hidden;padding-right:280px"><script type="text/javascript" src="/js/mo.min.js"></script><style>@media (min-width:768px) and (max-width:991px){body .header-innerr{width:700px!important}}.header-innerr{margin:0 auto;padding:100px 0 70px;width:880px}@media (min-width:1600px){.container .header-innerr{width:1200px}}.header-innerr{position:relative}.header-innerr{padding:20px 0 0}.header-innerr:after,.header-innerr:before{content:" ";display:table}.header-innerr:after{clear:both}@media (max-width:767px){.header-innerr{width:auto;padding:10px;margin-bottom:-20px}}</style><div class="container sidebar-position-left page-post-detail"><div class="headband"></div><header id="header" class="header"><div class="header-inner"><div class="site-brand-wrapper"><div class="site-meta"><link href="https://fonts.font.im/css?family=Merienda" rel="stylesheet"><div class="custom-logo-site-title"><a href="/" class="brand" rel="start"><span class="logo-line-before"><i></i></span> <span class="site-title" style="font-family:Merienda;font-size:1.3rem">MrBird</span> <span class="logo-line-after"><i></i></span></a></div><p class="site-subtitle"></p></div><div class="site-nav-toggle"><button><span class="btn-bar"></span> <span class="btn-bar"></span> <span class="btn-bar"></span></button></div></div><nav class="site-nav"><ul id="menu" class="menu"><li class="menu-item menu-item-home"><a href="/" rel="section">HOME</a></li><li class="menu-item menu-item-archives"><a href="/archives/" rel="section">ARCHIVES</a></li><li class="menu-item menu-item-tags"><a href="/tags/" rel="section">TAGS</a></li><li class="menu-item menu-item-friends"><a href="/friends/" rel="section">FRIENDS</a></li><div class="sidebar-toggle" style="display:none"><div class="sidebar-toggle-line-wrap"><span class="sidebar-toggle-line sidebar-toggle-line-first"></span> <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span> <span class="sidebar-toggle-line sidebar-toggle-line-last"></span></div></div></ul><div class="site-search"><div class="popup search-popup local-search-popup"><div class="local-search-header clearfix"><span class="search-icon"><i class="fa fa-search"></i> </span><span class="popup-btn-close"><i class="fa fa-times-circle"></i></span><div class="local-search-input-wrapper"><input autocomplete="off" placeholder="Search" spellcheck="false" type="text" id="local-search-input"></div></div><div id="local-search-result"></div></div></div></nav></div><div class="header-innerr"><div class="note info" style="margin:0;letter-spacing:.15px">🐤手把手教你搭建<strong>Spring Cloud微服务权限系统</strong>（从零到部署）：<a style="color:#40dab2;font-weight:600" href="https://www.kancloud.cn/mrbird/spring-cloud" target="_blank">https://www.kancloud.cn/mrbird/spring-cloud</a></div></div></header><main id="main" class="main"><div class="main-inner"><div class="content-wrap"><div id="content" class="content"><div id="posts" class="posts-expand"><article class="post post-type-normal" itemscope itemtype="http://schema.org/Article"><link itemprop="mainEntityOfPage" href="http://mrbird.cc/Vue-Learn-Note.html"><span hidden itemprop="author" itemscope itemtype="http://schema.org/Person"><meta itemprop="name" content="MrBird"><meta itemprop="description" content=""><meta itemprop="image" content="/images/blogImage.jpg"></span><span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization"><meta itemprop="name" content="MrBird"></span><header class="post-header"><h1 class="post-title" itemprop="name headline">Vue入门学习</h1><div class="post-meta"><span class="post-time"><span class="post-meta-item-icon"><i class="fa fa-calendar-o"></i> </span><span class="post-meta-item-text">Posted on</span> <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-05-25T15:56:54+08:00">2018-05-25 </time></span><span></span> <span class="post-meta-divider">|</span> <span class="page-pv"><i class="fa fa-laptop"></i>&nbsp;&nbsp;Visit count <span class="busuanzi-value" id="busuanzi_value_page_pv"></span></span></div></header><div class="post-body" itemprop="articleBody"><p>Vue (读音 /vjuː/，类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是，Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层，不仅易于上手，还便于与第三方库或既有项目整合。另一方面，当与现代化的工具链以及各种支持类库结合使用时，Vue 也完全能够为复杂的单页应用提供驱动。</p><div class="note danger"><p>本篇记录Vue学习过程，用于心得备忘，对外可读性差🙃，学习Vue还是以官方文档为主。</p></div><a id="more"></a><h2 id="Vue入门"><a href="#Vue入门" class="headerlink" title="Vue入门"></a>Vue入门</h2><p>通过一个Vue实现的todoList来入门：</p><p></p><p data-height="698" data-theme-id="30192" data-slug-hash="eQKOBN" data-default-tab="html" data-user="mrbird" data-pen-title="todo-list" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/eQKOBN/" target="_blank" rel="noopener">todo-list</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><ol><li><p><code>var app = new Vue({})</code>创建了一个实例，通过<code>el: &quot;#app&quot;</code>接管了ID为app的div的所有内容。</p></li><li><p><code>data</code>属性用于装载数据，包含<code>list</code>和<code>inputValue</code>。</p><ul><li><p><code>v-for</code>指令用于遍历集合，这里用于遍历<code>list</code>数组中的值；</p></li><li><p><code>v-model</code>指令用于双向数据绑定，即在<code>&lt;input type=&quot;text&quot; v-model=&quot;inputValue&quot;/&gt;</code>中输入的值会改变Vue实例中<code>inputValue</code>的值，通过JS改变Vue实例<code>inputValue</code>的值也会改变<code>&lt;input type=&quot;text&quot; v-model=&quot;inputValue&quot;/&gt;</code>中的值。</p></li></ul></li><li><p><code>@click</code>指令用于绑定事件，这里绑定了<code>createTodoList</code>事件，对应Vue实例<code>methods</code>中的<code>createTodoList</code>。</p></li></ol><h2 id="Vue组件"><a href="#Vue组件" class="headerlink" title="Vue组件"></a>Vue组件</h2><p>我们可以对一些常用的HTML片段抽取出来组装成一个Vue组件，Vue组件分为全局组件和局部组件。</p><h3 id="全局Vue组件"><a href="#全局Vue组件" class="headerlink" title="全局Vue组件"></a>全局Vue组件</h3><p>定义一个全局Vue组件改造上面的todoList：</p><p></p><p data-height="839" data-theme-id="30192" data-slug-hash="mQKbYa" data-default-tab="html" data-user="mrbird" data-pen-title="todo-list2" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/mQKbYa/" target="_blank" rel="noopener">todo-list2</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>这里我们使用<code>Vue.component(&#39;TodoItem&#39;,{})</code>定义了一个名称为<code>TodoItem</code>全局Vue组件，可以在任何Vue管理的Dom中使用：</p><ol><li><p><code>TodoItem</code>组件可以使用<code>&lt;todo-item&gt;</code>的方式使用，即大写可以转换为小写，第二个大写字母转小写后必须加上<code>-</code>前缀；</p></li><li><p><code>v-bind</code>指令用于绑定值，这里通过<code>v-bind:content</code>将<code>content</code>变量的值绑定为<code>item</code>(即list中的每个元素值)，通过<code>v-bind:index</code>将<code>index</code>变量的值绑定为<code>index</code>（即当前循环的下标）。<code>v-bind</code>可以简写为<code>:</code>；</p></li><li><p><code>props</code>属性用于向子组件传递数据，这里接收了由<code>:bind</code>指令传递了从父组件绑定过来的<code>index</code>和<code>content</code>变量；</p></li><li><p><code>template</code>定义了模板，即这个Vue组件呈现的样子（通常都是一段HTML加上父组件传递过来的变量值）。</p></li></ol><p>在这个过程中，我们除了学会了怎么定义全局Vue组件外，还学会了怎么从父组件中往子组件传值。</p><div class="note info"><p><code>&lt;div id=&quot;app&quot;&gt;</code>这个Dom结构已经被Vue接管，其内部又包含了<code>&lt;todo-item&gt;</code>Vue组件，所以我们将<code>&lt;div id=&quot;app&quot;&gt;</code>称之为父组件，<code>&lt;todo-item&gt;</code>称之为子组件。</p></div><h3 id="局部Vue组件"><a href="#局部Vue组件" class="headerlink" title="局部Vue组件"></a>局部Vue组件</h3><p>定义一个局部组件来改造上面的todoList：</p><p></p><p data-height="1057" data-theme-id="30192" data-slug-hash="pQKoPR" data-default-tab="html" data-user="mrbird" data-pen-title="todo-list3" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/pQKoPR/" target="_blank" rel="noopener">todo-list3</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>这里我们定义了一个局部JS对象<code>TodoItem</code>，然后在Vue实例<code>app</code>中的<code>components</code>属性中引入了该对象，名称依旧是<code>TodoItem</code>，这种就是局部Vue组件。</p><p>这里主要记录下该局部组件中<code>handleItemClick</code>方法的实现过程：</p><ol><li><p>我们在子组件<code>TodoItem</code>中定义了一个<code>handleItemClick</code>方法；</p></li><li><p><code>handleItemClick</code>方法里通过<code>this.$emit(&#39;delete&#39;, this.index)</code>向父组件传递一个事件，事件名称为<code>delete</code>,事件包含一个<code>index</code>参数。</p></li><li><p>子组件的<code>@delete</code>监听事件对应2中传递过来的<code>delete</code>事件，监听的方法为父组件的<code>deleteTodoList</code>方法，该方法中接受了2中传递过来的<code>index</code>参数，然后就可以在该方法中实现想要的逻辑了（这里为删除对应的点击对象）。</p></li></ol><p>在这个过程中，我们除了学会了怎么定义局部Vue组件外，还学会了怎么从子组件中往父组件传值。</p><div class="note info"><p>emit: 英[iˈmɪt],美[ɪˈmɪt] vt.发出; 发射</p></div><h2 id="Vue实例生命周期"><a href="#Vue实例生命周期" class="headerlink" title="Vue实例生命周期"></a>Vue实例生命周期</h2><p>Vue实例从创建到销毁包含了多个生命周期，如下图所示：</p><p><img style="width:35rem" src="img/lifecycle.png"></p><p>这个过程中包含了好几个生命周期函数，在相应的时间点会自动执行：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>vue实例生命周期函数<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">        el: <span class="string">"#app"</span>,</span></span><br><span class="line"><span class="xml">        template: '<span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;&#123;test&#125;&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span>',</span></span><br><span class="line"><span class="undefined">        data: &#123;</span></span><br><span class="line"><span class="javascript">            test: <span class="string">'hello world'</span></span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        beforeCreate: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"beforeCreate"</span>);</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        created: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"created"</span>);</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        beforeMount: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="keyword">this</span>.$el);</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"beforeMount"</span>);</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        mounted: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="keyword">this</span>.$el);</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"mounted"</span>);</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        beforeUpdate: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"beforeUpdate"</span>)</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        updated: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"updated"</span>);</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        beforeDestroy: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"beforeDestroy"</span>)</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        destroyed: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="built_in">console</span>.log(<span class="string">"destroyed"</span>);</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="undefined">    &#125;);</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p></p><p>其实，除了上面8个生命周期函数外，Vue还包含3个特殊的生命周期函数：<a href="https://cn.vuejs.org/v2/api/#activated" target="_blank" rel="noopener">activated</a>，<a href="https://cn.vuejs.org/v2/api/#deactivated" target="_blank" rel="noopener">deactivated</a> 和 <a href="https://cn.vuejs.org/v2/api/#errorCaptured" target="_blank" rel="noopener">errorCaptured</a>。</p><h2 id="计算属性，方法和监听器"><a href="#计算属性，方法和监听器" class="headerlink" title="计算属性，方法和监听器"></a>计算属性，方法和监听器</h2><h3 id="计算属性"><a href="#计算属性" class="headerlink" title="计算属性"></a>计算属性</h3><p>一个计算属性的例子：</p><p></p><p data-height="717" data-theme-id="30192" data-slug-hash="aPvPvo" data-default-tab="html" data-user="mrbird" data-pen-title="计算属性" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/aPvPvo/" target="_blank" rel="noopener">计算属性</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>使用<code>computed</code>计算了<code>fullName</code>属性，值为<code>firstName+lastName</code>。计算属性具有缓存功能，当<code>firstName</code>和<code>lastName</code>都不改变的时候，<code>fullName</code>不会重新计算，比如我们改变<code>age</code>的值，<code>fullName</code>的值是不需要重新计算的：</p><p><img src="img/QQ截图20181127223411.png" alt="QQ截图20181127223411.png"></p><h3 id="方法"><a href="#方法" class="headerlink" title="方法"></a>方法</h3><p>使用方法也可以实现上面的功能：</p><p></p><p data-height="593" data-theme-id="30192" data-slug-hash="gQdMaj" data-default-tab="html" data-user="mrbird" data-pen-title="todo-list5" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/gQdMaj/" target="_blank" rel="noopener">todo-list5</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>不过<code>methods</code>并没有缓存特性，比如我们改变<code>age</code>的值，<code>fullName()</code>方法会被执行一遍：</p><p><img src="img/QQ截图20181127224756.png" alt="QQ截图20181127224756.png"></p><h3 id="监听器"><a href="#监听器" class="headerlink" title="监听器"></a>监听器</h3><p>使用监听器也可以实现上面的功能：</p><p></p><p data-height="683" data-theme-id="30192" data-slug-hash="jQvrzP" data-default-tab="html" data-user="mrbird" data-pen-title="todo-list6" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/jQvrzP/" target="_blank" rel="noopener">todo-list6</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>这里监听了<code>firstName</code>和<code>lastName</code>的值，当它们任何一个改变的时侯<code>fullName</code>也跟变，我们改变<code>age</code>的值，<code>fullName</code>的值不会被重新计算，也具有缓存特性（不过代码比<code>computed</code>啰嗦）:</p><p><img src="img/QQ截图20181127225929.png" alt="QQ截图20181127225929.png"></p><div class="note info"><p>当一个功能可以用上面三个方法来实现的时候，明显使用<code>computed</code>更合适，代码简单也有缓存特性。</p></div><h2 id="computed的getter和setter"><a href="#computed的getter和setter" class="headerlink" title="computed的getter和setter"></a>computed的getter和setter</h2><p>将上面计算属性的例子改为下面的形式：</p><p></p><p data-height="829" data-theme-id="30192" data-slug-hash="EGVraN" data-default-tab="html,result" data-user="mrbird" data-pen-title="get set" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/EGVraN/" target="_blank" rel="noopener">get set</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p><img src="img/QQ截图20181127231739.png" alt="QQ截图20181127231739.png"></p><p>通过这种方式，我们可以在改变计算属性值的同时也改变和计算属性相关联的属性值。</p><h2 id="深入理解Vue组件"><a href="#深入理解Vue组件" class="headerlink" title="深入理解Vue组件"></a>深入理解Vue组件</h2><h3 id="is"><a href="#is" class="headerlink" title="is"></a>is</h3><p>先来看一个bug，下面是一个简单的Vue组件使用：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>title<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tbody</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">row</span>&gt;</span><span class="tag">&lt;/<span class="name">row</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">row</span>&gt;</span><span class="tag">&lt;/<span class="name">row</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">row</span>&gt;</span><span class="tag">&lt;/<span class="name">row</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tbody</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    Vue.component(<span class="string">'row'</span>, &#123;</span></span><br><span class="line"><span class="xml">        template: '<span class="tag">&lt;<span class="name">tr</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>hello world<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span>'</span></span><br><span class="line"><span class="undefined">    &#125;);</span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">        el: <span class="string">"#app"</span></span></span><br><span class="line"><span class="undefined">    &#125;);</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p></p><p>虽然其在页面上看上去是正常的，但是查看器DOM结构就能发现问题：</p><p><img src="img/QQ截图20181203214211.png" alt="QQ截图20181203214211.png"></p><p>可看到table的结构是错误的，因为HTML5规范只允许<code>&lt;tbody&gt;</code>下面紧跟着<code>&lt;tr&gt;</code>标签，类似的<code>&lt;ul&gt;</code>下只能紧跟着<code>&lt;li&gt;</code>标签。为了解决这个问题，我们可以用<code>is</code>来改写代码：</p><p></p><p data-height="657" data-theme-id="30192" data-slug-hash="QJVNjm" data-default-tab="html" data-user="mrbird" data-pen-title="is" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/QJVNjm/" target="_blank" rel="noopener">is</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><h3 id="子组件中的data应该为function"><a href="#子组件中的data应该为function" class="headerlink" title="子组件中的data应该为function"></a>子组件中的data应该为function</h3><p>改一下上面的例子：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">"en"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">"UTF-8"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>title<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"</span>&gt;</span><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">table</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">tbody</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">tr</span> <span class="attr">is</span>=<span class="string">"row"</span>&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">tr</span> <span class="attr">is</span>=<span class="string">"row"</span>&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="name">tr</span> <span class="attr">is</span>=<span class="string">"row"</span>&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="name">tbody</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">table</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    Vue.component(<span class="string">'row'</span>, &#123;</span></span><br><span class="line"><span class="javascript">        data: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">                content: <span class="string">'hello world.'</span></span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="xml">        template: '<span class="tag">&lt;<span class="name">tr</span>&gt;</span><span class="tag">&lt;<span class="name">td</span>&gt;</span>&#123;&#123;content&#125;&#125;<span class="tag">&lt;/<span class="name">td</span>&gt;</span><span class="tag">&lt;/<span class="name">tr</span>&gt;</span>'</span></span><br><span class="line"><span class="undefined">    &#125;);</span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> app = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">        el: <span class="string">"#app"</span></span></span><br><span class="line"><span class="undefined">    &#125;);</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure><p></p><p>如果data只是一个JS对象的话，Vue将抛出异常，之所以有这样的限制是因为子组件可能会在不同的地方多次引用，为了保持数据的作用域不一样（相互独立，互不影响），所以使用函数包裹了下。</p><h3 id="ref"><a href="#ref" class="headerlink" title="ref"></a>ref</h3><p>在使用Vue的时候，总有不得不去操作DOM的时候，这时候可以使用<code>ref</code>来完成。</p><p><strong>在DOM中使用</strong></p><p>直接举个例子，使用<code>ref</code>来获取<code>div</code>标签中的内容：</p><p></p><p data-height="565" data-theme-id="30192" data-slug-hash="rQRoKN" data-default-tab="html,result" data-user="mrbird" data-pen-title="ref1" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/rQRoKN/" target="_blank" rel="noopener">ref1</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>使用<code>ref</code>让<code>div</code>变成一个引用，名称为<code>div</code>，然后在<code>hello()</code>方法中，<code>this.$refs</code>表示当前Vue实例中的所有引用，<code>this.$refs.div</code>这里获取的是<code>&lt;div ref=&quot;div&quot;&gt;</code>这个DOM对象。</p><p><strong>在Vue组件中使用</strong></p><p>用Vue编写个求和的例子：</p><p></p><p data-height="950" data-theme-id="30192" data-slug-hash="rQRPae" data-default-tab="html,result" data-user="mrbird" data-pen-title="ref2" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/rQRPae/" target="_blank" rel="noopener">ref2</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>这里ref的引用是一个Vue组件。可以自个console打印看看。</p><h3 id="父组件向子组件传值"><a href="#父组件向子组件传值" class="headerlink" title="父组件向子组件传值"></a>父组件向子组件传值</h3><div class="note danger"><p>Vue规定，子组件不能直接修改父组件中传递过来的值。因为如果传递的是一个对象的话，你在一个子组件中修改了对象的属性值，很有可能别的子组件也用到了这个属性，那么就会一起修改了。变通的方法是，子组件去复制一份父组件传递过来的数据，然后修改这份拷贝。</p></div><h3 id="组件参数校验"><a href="#组件参数校验" class="headerlink" title="组件参数校验"></a>组件参数校验</h3><p>父组件往子组件传递参数的时候，子组件可以对这些参数的值进行一些规则校验，校验不通过Vue会抛出警告：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">Vue.component(<span class="string">'my-component'</span>, &#123;</span><br><span class="line">  props: &#123;</span><br><span class="line">    <span class="comment">// 基础的类型检查 (`null` 匹配任何类型)</span></span><br><span class="line">    propA: <span class="built_in">Number</span>,</span><br><span class="line">    <span class="comment">// 多个可能的类型</span></span><br><span class="line">    propB: [<span class="built_in">String</span>, <span class="built_in">Number</span>],</span><br><span class="line">    <span class="comment">// 必填的字符串</span></span><br><span class="line">    propC: &#123;</span><br><span class="line">      type: <span class="built_in">String</span>,</span><br><span class="line">      required: <span class="literal">true</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// 带有默认值的数字</span></span><br><span class="line">    propD: &#123;</span><br><span class="line">      type: <span class="built_in">Number</span>,</span><br><span class="line">      <span class="keyword">default</span>: <span class="number">100</span></span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// 带有默认值的对象</span></span><br><span class="line">    propE: &#123;</span><br><span class="line">      type: <span class="built_in">Object</span>,</span><br><span class="line">      <span class="comment">// 对象或数组默认值必须从一个工厂函数获取</span></span><br><span class="line">      <span class="keyword">default</span>: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> &#123; <span class="attr">message</span>: <span class="string">'hello'</span> &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;,</span><br><span class="line">    <span class="comment">// 自定义验证函数</span></span><br><span class="line">    propF: &#123;</span><br><span class="line">      validator: <span class="function"><span class="keyword">function</span> (<span class="params">value</span>) </span>&#123;</span><br><span class="line">        <span class="comment">// 这个值必须匹配下列字符串中的一个</span></span><br><span class="line">        <span class="keyword">return</span> [<span class="string">'success'</span>, <span class="string">'warning'</span>, <span class="string">'danger'</span>].indexOf(value) !== <span class="number">-1</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><h3 id="给组件绑定原生事件"><a href="#给组件绑定原生事件" class="headerlink" title="给组件绑定原生事件"></a>给组件绑定原生事件</h3><p>如果我们在组件上绑定一个监听事件，其并不会直接调用父组件的方法，如下所示，下面的点击事件是不会被触发的：</p><p></p><p data-height="603" data-theme-id="30192" data-slug-hash="bQJZPW" data-default-tab="html,result" data-user="mrbird" data-pen-title=".native" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/bQJZPW/" target="_blank" rel="noopener">.native</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>因为这样写实际上<code>@click</code>是子组件向父组件抛出的一个监听事件，这里子组件并没有通过<code>this.$emit(&#39;click&#39;)</code>向父组件传递这个事件。如果想要在组件上绑定原生的事件，只需要改为<a href="mailto:`@click.native" target="_blank" rel="noopener">`@click.native</a>`即可：</p><p></p><p data-height="639" data-theme-id="30192" data-slug-hash="wQZZKe" data-default-tab="html,result" data-user="mrbird" data-pen-title=".native2" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/wQZZKe/" target="_blank" rel="noopener">.native2</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><h3 id="非父子组件传值"><a href="#非父子组件传值" class="headerlink" title="非父子组件传值"></a>非父子组件传值</h3><p>父子组件传值上面已经介绍了，那非父子组件传值（不是直接的父子关系）呢？比如：</p><p><img alt="" style="width:55rem" src="img/components.png"></p><p>第一层如何与第三层之间传值呢？相同层级之间的组件又如何相互传值呢？有两种办法：</p><ol><li><p>vuex（后面再说）</p></li><li><p>总线机制（bus/发布订阅模式/观察者模式）</p></li></ol><p>看一个总线机制的例子（点击child-one会把child-one的innerHTML值传递给child-two）：</p><p></p><p data-height="951" data-theme-id="30192" data-slug-hash="gQyNbJ" data-default-tab="html,result" data-user="mrbird" data-pen-title="bus" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/gQyNbJ/" target="_blank" rel="noopener">bus</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>解释一下上面的实现过程：</p><ol><li><p>通过<code>Vue.prototype.bus = new Vue()</code>实现了在每个Vue实例中添加了一个bus属性，这个bus属性为一个Vue实例，拥有Vue的所有特性。所以在每个Vue实例中都会有一个bus属性，属性值都指向同一个Vue实例；</p></li><li><p>创建了两个兄弟子组件<code>child-one</code>和<code>child-two</code>；</p></li><li><p>在子组件<code>child-one</code>中有一个<code>handleClick</code>事件，事件里通过<code>this.bus.$emit</code>抛出了一个<code>change</code>事件，并携带一个参数，值为<code>child-one</code>的innerHTML。之所以可以通过<code>this.bus.$emit</code>抛出，是因为如上面所说的那样，每个Vue实例都携带了一个<code>bus</code>属性，该属性指向一个Vue实例；</p></li><li><p><code>child-one</code>抛出的<code>change</code>事件可以在任何的Vue实例中通过<code>this.bus.$on</code>来监听到。所以我们可以在<code>child-two</code>里通过调用<code>this.bus.$on</code>来监听，但在哪里监听这个事件好呢？我们可以借助Vue的生命周期钩子函数<code>mounted</code>来监听<code>change</code>事件；</p></li></ol><p>上面主要有两个技巧：① 让所有Vue实例拥有同一个属性；② 这个属性也是一个Vue实例。其实就是强行让非父子组件扯上关系，搭建这个关系的桥梁就是上面定义的bus。</p><p>如果只是简单的非父子组件之间的值的传递的话，全局Vue属性bus也可以指向一个简单对象，如下所示：</p><p></p><p data-height="914" data-theme-id="30192" data-slug-hash="oQOKyx" data-default-tab="html,result" data-user="mrbird" data-pen-title="bus1" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/oQOKyx/" target="_blank" rel="noopener">bus1</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>效果就是，直接点击<code>child-two</code>弹出<code>init</code>；先点击<code>child-one</code>改变<code>this.bus.name</code>的值为<code>one</code>，再点击<code>child-two</code>将弹出<code>one</code>。</p><h3 id="插槽slot"><a href="#插槽slot" class="headerlink" title="插槽slot"></a>插槽slot</h3><p>插槽要实现的是父组件优雅的往子组件传递DOM结构。<a href="https://cn.vuejs.org/v2/guide/components-slots.html" target="_blank" rel="noopener">https://cn.vuejs.org/v2/guide/components-slots.html</a>。</p><h3 id="作用域插槽"><a href="#作用域插槽" class="headerlink" title="作用域插槽"></a>作用域插槽</h3><p>有的时候你希望提供的组件带有一个可从子组件获取数据的可复用的插槽，即从子组件获取的数据在父组件中可以以任何形式展现，这种插槽就是作用域插槽，看个例子：</p><p></p><p data-height="789" data-theme-id="30192" data-slug-hash="EOBYyj" data-default-tab="html" data-user="mrbird" data-pen-title="slot1" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/EOBYyj/" target="_blank" rel="noopener">slot1</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p>子组件里在插槽中使用<code>:item=item</code>绑定了list中的每一项数据，然后父组件中使用该插槽的时候用<code>slot-scope=&quot;props&quot;</code>接收了这些数据。</p><h3 id="动态组件"><a href="#动态组件" class="headerlink" title="动态组件"></a>动态组件</h3><p>看个例子：</p><p></p><p data-height="691" data-theme-id="30192" data-slug-hash="XyLWjR" data-default-tab="html" data-user="mrbird" data-pen-title="dynamic" class="codepen">See the Pen <a href="https://codepen.io/mrbird/pen/XyLWjR/" target="_blank" rel="noopener">dynamic</a> by wuyouzhuguli (<a href="https://codepen.io/mrbird" target="_blank" rel="noopener">@mrbird</a>) on <a href="https://codepen.io" target="_blank" rel="noopener">CodePen</a>.</p><p></p><script async src="https://static.codepen.io/assets/embed/ei.js"></script><p><code>&lt;component&gt;</code>标签用于加载动态组件，加载哪个名字的组件根据<code>:is</code>指定的值来选择。这里通过<code>change</code>事件来改变<code>type</code>的值。</p><h2 id="Vue动画特效"><a href="#Vue动画特效" class="headerlink" title="Vue动画特效"></a>Vue动画特效</h2><p>Vue官方文档写的很详细，<a href="https://cn.vuejs.org/v2/guide/transitions.html" target="_blank" rel="noopener">https://cn.vuejs.org/v2/guide/transitions.html</a>。</p><h2 id="构建第一个Vue项目"><a href="#构建第一个Vue项目" class="headerlink" title="构建第一个Vue项目"></a>构建第一个Vue项目</h2><p>第一步，安装<code>vue-cli</code>：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cnpm install --global vue-cli</span><br></pre></td></tr></table></figure><p></p><p>安装好后，初始化一个简单的Vue项目：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">vue init webpack vue-project-test</span><br></pre></td></tr></table></figure><p></p><p>过程中需要步骤确认：</p><p><img src="img/QQ截图20181207221803.png" alt="QQ截图20181207221803.png"></p><p>初始化完毕后，启动项目：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> vue-project-test</span><br><span class="line">npm run dev</span><br></pre></td></tr></table></figure><p></p><p><img src="img/QQ截图20181207221947.png" alt="QQ截图20181207221947.png"></p><p>访问<a href="http://localhost:8080/#/" target="_blank" rel="noopener">http://localhost:8080/</a>：</p><p><img src="img/QQ截图20181207222107.png" alt="QQ截图20181207222107.png"></p><p>项目构建成功！前端也挺好玩的😋</p><h2 id="项目结构介绍"><a href="#项目结构介绍" class="headerlink" title="项目结构介绍"></a>项目结构介绍</h2><p>打开上面创建好的vue-project-test，项目目录如下所示：</p><p><img src="img/QQ截图20181207224554.png" alt="QQ截图20181207224554.png"></p><p>先从外部的文件说起：</p><ol><li><p>package.json：第三方依赖配置；</p></li><li><p>package-lock.json：package.json的锁文件，确定第三方依赖的版本，保持团队协作上版本的统一；</p></li><li><p>index.html：项目首页模板；</p></li><li><p>.postcssrc.js：postcss配置项（暂时不懂干嘛的）；</p></li><li><p>.eslintrc.js：js语法检查；</p></li><li><p>.eslintignore：配置排除js检查；</p></li><li><p>.editorconfig：编辑配置；</p></li><li><p>.babelrc：将Vue文件转换为浏览器能够识别的html；</p></li></ol><p>再来看目录：</p><ol><li><p>static/：项目静态资源存放，里面的资源直接可以通过URL访问；</p></li><li><p>node_modules/：项目依赖的第三方包；</p></li><li><p>src/：包含项目文件，结构如下所示：</p><p><img src="img/QQ截图20181208110210.png" alt="QQ截图20181208110210.png"></p><ul><li><p>main.js：整个项目入口文件；</p></li><li><p>App.vue：项目的根组件；</p></li><li><p>router/：项目路由配置处；</p></li><li><p>components/：存放项目所用到的组件；</p></li><li><p>assets/：存放项目用到的图片资源；</p></li></ul></li><li><p>config/：项目配置文件目录，修改需要重启项目；</p></li><li><p>build/：项目打包webpack配置处。</p></li></ol><h3 id="单文件Vue组件"><a href="#单文件Vue组件" class="headerlink" title="单文件Vue组件"></a>单文件Vue组件</h3><p>当一个文件以.vue结尾的时候，他就是一个单文件Vue组件，比如上面的App.vue:</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">img</span> <span class="attr">src</span>=<span class="string">"./assets/logo.png"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">router-view</span>/&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">  name: <span class="string">'App'</span></span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="css"><span class="selector-id">#app</span> &#123;</span></span><br><span class="line"><span class="undefined">  font-family: 'Avenir', Helvetica, Arial, sans-serif;</span></span><br><span class="line"><span class="undefined">  -webkit-font-smoothing: antialiased;</span></span><br><span class="line"><span class="undefined">  -moz-osx-font-smoothing: grayscale;</span></span><br><span class="line"><span class="undefined">  text-align: center;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">color</span>: <span class="selector-id">#2c3e50</span>;</span></span><br><span class="line"><span class="undefined">  margin-top: 60px;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure><p></p><p>可以看到，单文件Vue组件主要包含了三个部分：templage、script和style。</p><h3 id="Vue路由"><a href="#Vue路由" class="headerlink" title="Vue路由"></a>Vue路由</h3><p>路由就是根据不同的URL返回不同的内容给用户。</p><p>可以看到上面单文件Vue组件里有个<code>&lt;router-view/&gt;</code>标签，它显示的是当前路由地址对应的内容，当前地址就是<a href="http://localhost:8080/#/" target="_blank" rel="noopener">http://localhost:8080/#/</a>，它对应的内容是下面红框部分：</p><p><img src="img/QQ截图20181208113429.png" alt="QQ截图20181208113429.png"></p><p>那它为什么就会显示出这个部分的内容呢？下面讲解下：</p><p>在main.js中：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// The Vue build version to load with the `import` command</span></span><br><span class="line"><span class="comment">// (runtime-only or standalone) has been set in webpack.base.conf with an alias.</span></span><br><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> App <span class="keyword">from</span> <span class="string">'./App'</span></span><br><span class="line"><span class="keyword">import</span> router <span class="keyword">from</span> <span class="string">'./router'</span></span><br><span class="line"></span><br><span class="line">Vue.config.productionTip = <span class="literal">false</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* eslint-disable no-new */</span></span><br><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  router,</span><br><span class="line">  components: &#123; App &#125;,</span><br><span class="line">  template: <span class="string">'&lt;App/&gt;'</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><p>这里我们引入了router，并在Vue实例中使用了。</p><div class="note info"><p>ES6语法，当键值对名称相同时，可以简化，比如上面<code>router</code>指的是<code>router: router</code>；<code>components: { App }</code>指的是<code>components: { App: App }</code></p></div><p><code>import router from &#39;./router&#39;</code>会帮我们引入当前目录下router文件夹下的内容，router目录下是一个index.js：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Router <span class="keyword">from</span> <span class="string">'vue-router'</span></span><br><span class="line"><span class="keyword">import</span> HelloWorld <span class="keyword">from</span> <span class="string">'@/components/HelloWorld'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Router)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Router(&#123;</span><br><span class="line">  routes: [</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/'</span>,</span><br><span class="line">      name: <span class="string">'HelloWorld'</span>,</span><br><span class="line">      component: HelloWorld</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>上面配置了一个路由规则，当访问项目根路径的时候，引入名称为<code>Helloworld</code>的Vue组件，这个组件来自<code>&#39;@/components/HelloWorld&#39;</code>，其中<code>@</code>表示<code>src</code>这个目录。</p><p>HelloWorld.vue文件内容：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"hello"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h1</span>&gt;</span>&#123;&#123; msg &#125;&#125;<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h2</span>&gt;</span>Essential Links<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"https://vuejs.org"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          Core Docs</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"https://forum.vuejs.org"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          Forum</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"https://chat.vuejs.org"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          Community Chat</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"https://twitter.com/vuejs"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          Twitter</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">br</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"http://vuejs-templates.github.io/webpack/"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          Docs for This Template</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">h2</span>&gt;</span>Ecosystem<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">ul</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"http://router.vuejs.org/"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          vue-router</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"http://vuex.vuejs.org/"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          vuex</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"http://vue-loader.vuejs.org/"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          vue-loader</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">li</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">a</span></span></span><br><span class="line"><span class="tag">          <span class="attr">href</span>=<span class="string">"https://github.com/vuejs/awesome-vue"</span></span></span><br><span class="line"><span class="tag">          <span class="attr">target</span>=<span class="string">"_blank"</span></span></span><br><span class="line"><span class="tag">        &gt;</span></span><br><span class="line">          awesome-vue</span><br><span class="line">        <span class="tag">&lt;/<span class="name">a</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">li</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">ul</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">  name: <span class="string">'HelloWorld'</span>,</span></span><br><span class="line"><span class="undefined">  data () &#123;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">      msg: <span class="string">'Welcome to Your Vue.js App'</span></span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined">  &#125;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">&lt;!-- Add "scoped" attribute to limit CSS to this component only --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">style</span> <span class="attr">scoped</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="undefined">h1, h2 &#123;</span></span><br><span class="line"><span class="undefined">  font-weight: normal;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined">ul &#123;</span></span><br><span class="line"><span class="undefined">  list-style-type: none;</span></span><br><span class="line"><span class="undefined">  padding: 0;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined">li &#123;</span></span><br><span class="line"><span class="undefined">  display: inline-block;</span></span><br><span class="line"><span class="undefined">  margin: 0 10px;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined">a &#123;</span></span><br><span class="line"><span class="css">  <span class="selector-tag">color</span>: <span class="selector-id">#42b983</span>;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br></pre></td></tr></table></figure><p></p><p>所以首页红框内会显示这个内容。</p><h2 id="函数节流"><a href="#函数节流" class="headerlink" title="函数节流"></a>函数节流</h2><p>比如我们的在输入的时候需要监控keypress事件，在页面滚动的时候监控页面的滚动事件，这时候事件执行的频率会非常之高，这时候我们可以用下面这个方法来节流：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">data () &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123;</span><br><span class="line">    keyword: <span class="string">''</span>,</span><br><span class="line">    timer: <span class="literal">null</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br><span class="line">watch: &#123;</span><br><span class="line">  keyword () &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">this</span>.timer) &#123;</span><br><span class="line">      clearTimeout(<span class="keyword">this</span>.timer)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">this</span>.timer = setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// to something</span></span><br><span class="line">    &#125;, <span class="number">100</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面Vue监听了keyword变化，我们在监听函数里使用定时器的方式来节流，让频繁调用的时间延迟100毫秒，这个时间范围内只会执行一次监控事件。实际应用时，这个时间范围带来的节流影响肉眼上看不出区别即可。</p><h2 id="Vuex实现数据共享"><a href="#Vuex实现数据共享" class="headerlink" title="Vuex实现数据共享"></a>Vuex实现数据共享</h2><p>上面介绍了使用bus来进行非父子组件之间的传值，现在我们看看怎么通过Vuex来实现（官方推荐，更为强大方便）。来看下图:</p><p><img src="img/vuex.png" style="width:45rem"></p><p>当多个组件之间需要传递复杂的值的时候，我们就可以借助Vuex来实现。Vuex相当于是一个存储公共数据部分的地方（类似于仓库<strong>Store</strong>），当一个值被改变的时候，别的用到这个值的地方也会感应到改变。上图绿色虚线部分就是Vuex区域。</p><p>公共数据存储在<strong>State</strong>部分，组件（<strong>Vue compontents</strong>）可以直接通过<strong>Render</strong>方法引用。组件不能直接改变这个数据，需要通过调用<strong>Dispatch</strong>方法来改变<strong>Actions</strong>，由它来通过调用<strong>Commit</strong>方法来改变<strong>Mutations</strong>，最后由<strong>Mutations</strong>调用<strong>Mutate</strong>方法来改变公共数据。这个过程就对应上图的循环圈。</p><p>这个过程也不是绝对的，有的时候组件也可以直接通过调用Commit方法来改变Mutations，再由Mutations调用Mutate方法来改变公共数据。</p><p>Vuex安装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install vuex</span><br></pre></td></tr></table></figure><p></p><p><strong>Vuex使用</strong></p><div style="border-left:3px solid #42b983;display:block;padding-left:.6rem;margin:.5rem 0">创建一个Store</div><p>src下新建一个store目录，然后在下面创建index.js：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    name: <span class="string">'mrbird'</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><p>这里我们创建了一个Store，并定义了state，里面包含一个name属性，值为mrbird。</p><div style="border-left:3px solid #42b983;display:block;padding-left:.6rem;margin:.5rem 0">在main.js里引入Store</div><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">...</span><br><span class="line"><span class="keyword">import</span> store <span class="keyword">from</span> <span class="string">'./store'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* eslint-disable no-new */</span></span><br><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">'#app'</span>,</span><br><span class="line">  store,</span><br><span class="line">  ...</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>我们在main.js里引入了Store，即根组件里引入了，所以任何子组件都可以使用了。</p><div style="border-left:3px solid #42b983;display:block;padding-left:.6rem;margin:.5rem 0">使用Store里存的值</div><p>像下面这样使用：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$store.state.name</span><br></pre></td></tr></table></figure><p></p><p>这样就可以取出mrbird。</p><div style="border-left:3px solid #42b983;display:block;padding-left:.6rem;margin:.5rem 0">改变Store里存的值</div><p>在需要改变值的地方派发一个改变事件：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$store.dispatch(<span class="string">'changeName'</span>, <span class="string">'newName'</span>)</span><br></pre></td></tr></table></figure><p></p><p>然后在/store/index.js下添加actions：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    name: <span class="string">'mrbird'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  actions: &#123;</span><br><span class="line">    changeName (ctx, name) &#123;</span><br><span class="line">      ctx.commit(<span class="string">'changeName'</span>, name)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  mutations: &#123;</span><br><span class="line">    changeName (state, name) &#123;</span><br><span class="line">      state.name = name</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><p>可看到，actions里定义的changeName方法对应<code>this.$store.dispatch(&#39;changeName&#39;, name)</code>派发的方法，通过第一个入参<code>ctx</code>执行<code>ctx.commit(&#39;changeName&#39;, name)</code>，这里的<code>changeName</code>对应<code>mutations</code>里的<code>changeName</code>方法，最终我们可以在这个方法里改变state里的name的值。</p><p>上面这个过程对应图里流程，这个过程也可以简化👇</p><p>在需要改变值的地方执行下面语句：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$store.commit(<span class="string">'changeName'</span>, <span class="string">'newName'</span>)</span><br></pre></td></tr></table></figure><p></p><p>然后/store/index.js下直接这样写即可：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    name: <span class="string">'mrbird'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  mutations: &#123;</span><br><span class="line">    changeName (state, name) &#123;</span><br><span class="line">      state.name = name</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><h2 id="Vuex高级特性"><a href="#Vuex高级特性" class="headerlink" title="Vuex高级特性"></a>Vuex高级特性</h2><p>从Vuex里取出<code>state</code>里的值的时候，上面是这样写的：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$store.state.name</span><br></pre></td></tr></table></figure><p></p><p>这里可以简化一波：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; mapState &#125; <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  ...</span><br><span class="line">  computed: &#123;</span><br><span class="line">    ...mapState([<span class="string">'name'</span>])</span><br><span class="line">  &#125;</span><br><span class="line">  ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p></p><p>然后取值的地方直接<code>this.name</code>就行了。</p><p>也可以这样：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; mapState &#125; <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  ...</span><br><span class="line">  computed: &#123;</span><br><span class="line">    ...mapState(&#123;</span><br><span class="line">       currentUser: <span class="string">'user'</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">  ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p></p><p>然后取值的地方直接<code>this.currentUser</code>就行了。</p><p>取值的地方可以简化，那么改变值的地方也可以简化（import的时候也引入<code>mapMutations</code>）：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; mapMutations &#125; <span class="keyword">from</span> <span class="string">'vuex'</span></span><br></pre></td></tr></table></figure><p>然后在methods里这样：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">methods: &#123;</span><br><span class="line">  handleClick (name) &#123;</span><br><span class="line">    <span class="comment">// this.$store.commit('changeName', name)</span></span><br><span class="line">    <span class="keyword">this</span>.changeName(name)</span><br><span class="line">  &#125;,</span><br><span class="line">  ...mapMutations([<span class="string">'changeName'</span>])</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p></p><p>实际项目中，actions和mutations里的内容一般都非常多，所以我们可以将它们剥离出来，然后引入即可，就像下面这样：</p><p>新建mutations.js：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  changeName (state, name) &#123;</span><br><span class="line">    state.name = name</span><br><span class="line">    localStorage.name = name</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p></p><p>然后在store/index.js里引入：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"><span class="keyword">import</span> mutations <span class="keyword">from</span> <span class="string">'./mutations'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  ...</span><br><span class="line">  mutations</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><h3 id="Vuex-Getter"><a href="#Vuex-Getter" class="headerlink" title="Vuex Getter"></a>Vuex Getter</h3><p>Getter类似于Vuex版的computed，在store/index.js里定义Getter：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Vuex)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    name: <span class="string">'mrbird'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  getters: &#123;</span><br><span class="line">    getMessage (state) &#123;</span><br><span class="line">      <span class="keyword">return</span> state.name + <span class="string">'is so handsome'</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><p>引用的地方：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; mapGetters &#125; <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  ...</span><br><span class="line">  computed: &#123;</span><br><span class="line">    ...mapGetters([<span class="string">'getMessage'</span>])</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p></p><p>然后<code>this.getMessage</code>就会得到<code>mrbird is so handsome</code>信息了。</p><p>Getter详细文档： <a href="https://vuex.vuejs.org/zh/guide/getters.html" target="_blank" rel="noopener">https://vuex.vuejs.org/zh/guide/getters.html</a></p><h3 id="Vuex-Module"><a href="#Vuex-Module" class="headerlink" title="Vuex Module"></a>Vuex Module</h3><p>由于使用单一状态树，应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时，store 对象就有可能变得相当臃肿。</p><p>为了解决以上问题，Vuex 允许我们将 store 分割成模块（module）。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> moduleA = &#123;</span><br><span class="line">  state: &#123; ... &#125;,</span><br><span class="line">  mutations: &#123; ... &#125;,</span><br><span class="line">  actions: &#123; ... &#125;,</span><br><span class="line">  getters: &#123; ... &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> moduleB = &#123;</span><br><span class="line">  state: &#123; ... &#125;,</span><br><span class="line">  mutations: &#123; ... &#125;,</span><br><span class="line">  actions: &#123; ... &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> store = <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  modules: &#123;</span><br><span class="line">    a: moduleA,</span><br><span class="line">    b: moduleB</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">store.state.a <span class="comment">// -&gt; moduleA 的状态</span></span><br><span class="line">store.state.b <span class="comment">// -&gt; moduleB 的状态</span></span><br></pre></td></tr></table></figure><p></p><p>详细文档： <a href="https://vuex.vuejs.org/zh/guide/modules.html" target="_blank" rel="noopener">https://vuex.vuejs.org/zh/guide/modules.html</a></p><p><img src="img/QQ截图20181215211617.png" alt="QQ截图20181215211617.png"></p><h2 id="路由跳转"><a href="#路由跳转" class="headerlink" title="路由跳转"></a>路由跳转</h2><p>我们除了可以使用<code>&lt;router-link&gt;</code>创建 a 标签来定义导航链接，我们还可以借助 router 的实例方法，通过编写代码来实现：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">router.push(<span class="string">'/home'</span>)</span><br></pre></td></tr></table></figure><p></p><p>具体：<a href="https://router.vuejs.org/zh/guide/essentials/navigation.html" target="_blank" rel="noopener">https://router.vuejs.org/zh/guide/essentials/navigation.html</a></p><h2 id="路由参数传递"><a href="#路由参数传递" class="headerlink" title="路由参数传递"></a>路由参数传递</h2><p>当路由<code>path</code>中包含参数的时候，比如：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Router(&#123;</span><br><span class="line">  routes: [</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/detail/:id'</span>,</span><br><span class="line">      name: <span class="string">'Detail'</span>,</span><br><span class="line">      component: Detail</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p></p><p>在<code>Detail</code>组件中，我们就可以使用<code>this.$route.params.id</code>来获取了。</p><h2 id="localStorage"><a href="#localStorage" class="headerlink" title="localStorage"></a>localStorage</h2><p>H5中新增的可以存储数据的东东，类似cookie，但比cookie更简单。</p><p>改进一下上面Vuex的例子：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">  state: &#123;</span><br><span class="line">    name: localStorage.name || <span class="string">'mrbird'</span></span><br><span class="line">  &#125;,</span><br><span class="line">  mutations: &#123;</span><br><span class="line">    changeName (state, name) &#123;</span><br><span class="line">      state.name = name</span><br><span class="line">      localStorage.name = name</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>在mutations中，我们不但改变了<code>state.name</code>的值，还把值存到了<code>localStorage</code>中，这样即使浏览器刷新也不会重置回’mrbird’。</p><div class="note danger"><p>和cookie类似，localStorage也可以通过浏览器禁用，所以我们在使用localStorage的时候要用<code>try{}catch(){}</code>来处理，防止代码抛出异常无法正常运行。</p></div><h2 id="keep-alive"><a href="#keep-alive" class="headerlink" title="keep-alive"></a>keep-alive</h2><p><a href="https://cn.vuejs.org/v2/api/#keep-alive" target="_blank" rel="noopener">https://cn.vuejs.org/v2/api/#keep-alive</a></p><h2 id="组件的递归"><a href="#组件的递归" class="headerlink" title="组件的递归"></a>组件的递归</h2><p>当一个数据具有上下级，而且级数无法确定的时候，我们可以使用递归组件来展示我们的层级数据，看下面这个栗子：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"item"</span> <span class="attr">v-for</span>=<span class="string">"(item, index) of list"</span> <span class="attr">:key</span>=<span class="string">"index"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">"item-title border-bottom"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span> <span class="attr">class</span>=<span class="string">"item-title-icon"</span>&gt;</span><span class="tag">&lt;/<span class="name">span</span>&gt;</span></span><br><span class="line">        &#123;&#123;item.title&#125;&#125;</span><br><span class="line">      <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">v-if</span>=<span class="string">"item.children"</span> <span class="attr">class</span>=<span class="string">"item-chilren"</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">detail-list</span> <span class="attr">:list</span>=<span class="string">"item.children"</span>&gt;</span><span class="tag">&lt;/<span class="name">detail-list</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="javascript">  name: <span class="string">'DetailList'</span>,</span></span><br><span class="line"><span class="undefined">  data() &#123;</span></span><br><span class="line"><span class="javascript">    <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="undefined">      list: [</span></span><br><span class="line"><span class="undefined">        &#123;</span></span><br><span class="line"><span class="javascript">          title: <span class="string">'爷爷'</span>,</span></span><br><span class="line"><span class="undefined">          children: [</span></span><br><span class="line"><span class="undefined">            &#123;</span></span><br><span class="line"><span class="javascript">              title: <span class="string">'爸爸'</span></span></span><br><span class="line"><span class="undefined">            &#125;,</span></span><br><span class="line"><span class="undefined">            &#123;</span></span><br><span class="line"><span class="javascript">              title: <span class="string">'妈妈'</span>,</span></span><br><span class="line"><span class="undefined">              children: [</span></span><br><span class="line"><span class="undefined">                &#123;</span></span><br><span class="line"><span class="javascript">                  title: <span class="string">'小明'</span></span></span><br><span class="line"><span class="undefined">                &#125;</span></span><br><span class="line"><span class="undefined">              ]</span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">          ]</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="undefined">        &#123;</span></span><br><span class="line"><span class="javascript">          title: <span class="string">'奶奶'</span></span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">      ]</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined">  &#125;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p></p><p>这个组件叫<code>DetailList</code>，在循环中，通过<code>item.children</code>来判断是否有下级，有的话调用组件自身。这样就可以很简单的实现递归了。</p><h2 id="Vue项目打包上线"><a href="#Vue项目打包上线" class="headerlink" title="Vue项目打包上线"></a>Vue项目打包上线</h2><p>修改config/index.js：</p><p><img src="img/QQ截图20181213110050.png" alt="QQ截图20181213110050.png"></p><p>红框部分我们将<code>assetsPublicPath</code>指定为<code>/vue</code>。</p><p>接着在项目根目录执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run build</span><br></pre></td></tr></table></figure><p></p><p>打包完，命令行会提示：</p><p><img src="img/QQ截图20181213104836.png" alt="QQ截图20181213104836.png"></p><p>然后项目里会出现一个dist目录：</p><p><img src="img/QQ截图20181213105043.png" alt="QQ截图20181213105043.png"></p><p>我们在tomcat的webapps目录下也新建一个vue目录，然后把dist里的内容拷贝进去，然后启动tomcat，访问<a href="http://{ip}:{port}/vue" target="_blank" rel="noopener">http://{ip}:{port}/vue</a>就能看到项目了。</p><h2 id="异步组件加载"><a href="#异步组件加载" class="headerlink" title="异步组件加载"></a>异步组件加载</h2><p>查看打包目录下的js文件夹：</p><p><img src="img/QQ图片20181213112112.png" alt="QQ图片20181213112112.png"></p><p>项目所有的逻辑都被打包在了appXXXX.js里了，即在加载首页的时候，整个项目js逻辑都被加载了。如果项目规模很大，这个文件将可能达到MB级别。我们也可以将组件进行异步的加载来解决这个问题，比如在路由中，我们这样引用组件：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vue <span class="keyword">from</span> <span class="string">'vue'</span></span><br><span class="line"><span class="keyword">import</span> Router <span class="keyword">from</span> <span class="string">'vue-router'</span></span><br><span class="line"></span><br><span class="line">Vue.use(Router)</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">new</span> Router(&#123;</span><br><span class="line">  routes: [</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/'</span>,</span><br><span class="line">      name: <span class="string">'home'</span>,</span><br><span class="line">      component: <span class="function"><span class="params">()</span> =&gt;</span> <span class="keyword">import</span>(<span class="string">'@/pages/home/Home'</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/dept'</span>,</span><br><span class="line">      name: <span class="string">'dept'</span>,</span><br><span class="line">      component: <span class="function"><span class="params">()</span> =&gt;</span> <span class="keyword">import</span>(<span class="string">'@/pages/dept/Dept'</span>)</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/detail/:id'</span>,</span><br><span class="line">      name: <span class="string">'Detail'</span>,</span><br><span class="line">      component: <span class="function"><span class="params">()</span> =&gt;</span> <span class="keyword">import</span>(<span class="string">'@/pages/detail/Detail'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><code>component</code>里我们使用箭头函数来引入对应的组件，这样就实现了异步加载，重新打包项目，再次查看js文件夹：</p><p><img src="img/QQ截图20181213112523.png" alt="QQ截图20181213112523.png"></p><p>可以看到appxxxx.js已经被拆分了。</p><h2 id="自定义Vue插件"><a href="#自定义Vue插件" class="headerlink" title="自定义Vue插件"></a>自定义Vue插件</h2><p><img src="img/localstorage插件编写方法.png" alt="localstorage插件编写方法.png"></p><p>具体可查看：<a href="https://router.vuejs.org/zh/guide/advanced/lazy-loading.html" target="_blank" rel="noopener">https://router.vuejs.org/zh/guide/advanced/lazy-loading.html</a></p><script>$(".post-body a").not(".thispage").addClass("ignore-href").attr("target","_blank")</script></div><div></div><div><div style="padding:10px 0;margin:20px auto;width:90%;text-align:center;color:#878787"><div>请作者喝瓶肥宅水~</div><button id="rewardButton" style="margin-top:10px" disable="enable" onclick='var e=document.getElementById("QR");"none"===e.style.display?e.style.display="block":e.style.display="none"'><span style="height:46px;width:46px;line-height:46px;border-radius:50%;color:#fe5f55;font-weight:600;background:#ffd5be;border:none;box-shadow:0 4px 8px 0 rgba(255,213,190,.4)">￥</span></button><div id="QR" style="display:none"><div id="wechat" style="display:inline-block"><img id="wechat_qr" src="/img/wechat_pay.png" alt="MrBird WeChat Pay"></div><div id="alipay" style="display:inline-block"><img id="alipay_qr" src="/img/ali_pay.png" alt="MrBird Alipay"></div></div></div><style>#QR img{width:auto;margin:.8em 1em 0 1em}</style></div><div><ul class="post-copyright"><li class="post-copyright-author"><strong>本文作者：</strong> MrBird</li><li class="post-copyright-link"><strong>本文链接：</strong> <a href="http://mrbird.cc/Vue-Learn-Note.html" title="Vue入门学习">http://mrbird.cc/Vue-Learn-Note.html</a></li><li class="post-copyright-license"><strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="external nofollow" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明出处！</li></ul></div><footer class="post-footer"><div class="post-tags" style="margin-bottom:1.3rem"><a href="/tags/Vue/" rel="tag"># Vue</a></div><div class="post-nav"><div class="post-nav-next post-nav-item"><a href="/Spring-Security-OAuth2-Guide.html" rel="next" title="Spring Security OAuth2入门"><i class="fa fa-chevron-left"></i> Spring Security OAuth2入门</a></div><span class="post-nav-divider"></span><div class="post-nav-prev post-nav-item"><a href="/Spring-Security-OAuth2-Customize.html" rel="prev" title="Spring Security OAuth2自定义Token获取方式">Spring Security OAuth2自定义Token获取方式 <i class="fa fa-chevron-right"></i></a></div></div></footer></article><hr><div id="container"></div><div class="post-spread"><div id="comment-div"></div><style>.valine .vlist{margin-bottom:3rem}.valine .vwrap .vcontrol .col.col-60{text-align:left}.valine .vlist .vcard .vhead,.valine .vlist .vcard section .vfooter{text-align:left}.valine .vlist .vcard section{padding-bottom:.5rem!important}.vname{color:#42b983!important}.valine .vinfo .col{text-align:left;margin-left:-27rem}div#comment-div{margin-bottom:-8rem}.valine .vlist .vcard .vcontent .code,.valine .vlist .vcard .vcontent code,.valine .vlist .vcard .vcontent pre{background:#fbfbfb}.valine .vlist .vcard .vcontent a{color:#42b983}.valine .vlist .vcard .vimg{border-radius:3px}.valine .vbtn{border-radius:2px;padding:.3rem 1.25rem}.valine .vbtn:active,.valine .vbtn:hover{color:#42b983;border-color:#42b983;background-color:#fff}.valine .vwrap .vheader .vinput:focus{border-bottom-color:#42b983}.valine .vlist .vcard .vcontent.expand:before{background:-webkit-gradient(linear,left top,left bottom,from(hsla(0,0%,100%,0)),to(hsla(0,0%,100%,.2)));background:linear-gradient(180deg,hsla(0,0%,100%,0),hsla(0,0%,100%,.2))}.valine .vlist .vcard .vcontent.expand:after{content:"点击展开";font-size:.4rem;text-align:right;left:-1rem;background:hsla(0,0%,100%,.2)}.valine .vlist .vcard section .vfooter .vat{color:#b3b3b3}.valine .vlist .vcard section .vfooter .vat:hover{color:#42b983}.vcontent img{margin:0}.valine .info{display:none}</style><script type="text/javascript" src="/js/av.min.js"></script><script type="text/javascript" src="/js/Valine.min.js"></script><script type="text/javascript" src="/js/activate-power-mode.js"></script><script>POWERMODE.colorful=!0,POWERMODE.shake=!1,document.body.addEventListener("input",POWERMODE),new Valine({el:"#comment-div",notify:!1,verify:!0,appId:"SMcDFP1bN1jgb9Lo8JmtICHm-gzGzoHsz",appKey:"dH4nrUrt3V5XiJiI6Qyejnbi",placeholder:"",path:window.location.pathname,avatar:"monsterid",guest_info:["nick","mail","link"]});var chicken='<a href="#"><img src="https://image.uisdc.com/wp-content/uploads/2018/06/uisdc-chat-chicken.gif" class="checken"></a>';$("#comment-div").prepend(chicken)</script></div></div><script>var $bqinline=$("img[alt='bq-inline']");$bqinline.css({width:"2.3rem",height:"2.3rem",display:"inline","vertical-align":"text-bottom"})</script></div><div class="comments" id="comments"></div></div><aside id="sidebar" class="sidebar" onselectstart="return!1"><div class="sidebar-inner"><ul class="sidebar-nav motion-element"><li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">Contents</li><li class="sidebar-nav-overview" data-target="site-overview">Site Preview</li></ul><section class="site-overview sidebar-panel"><div class="sidebar-sticky sticky"><div itemscope itemtype="http://schema.org/Person"><div class="author__avatar"><img src="/images/blogImage.jpg" class="author__avatar" alt="MrBird" itemprop="image"></div><div class="author__content"><h3 class="author__name" itemprop="name">MrBird's Blog</h3><p class="author__bio" itemprop="description">A simple blog, code repository, just keep blogging</p></div><div class="author__urls-wrapper"><button class="btn btn--inverse">Follow</button><ul class="author__urls social-icons"><li><a href="http://map.baidu.com/?newmap=1&s=s%26wd%3D%E7%A6%8F%E5%B7%9E%E5%B8%82%26c%3D300&from=alamap&tpl=mapcity" target="_blank" itemprop="url" class="ignore-href"><i class="fa fa-fw fa-map-marker" aria-hidden="true"></i>&nbsp;&nbsp;FuZhou,CN</a></li><li><a href="https://love.mrbird.cc" target="_blank" itemprop="url" class="ignore-href"><i class="fa fa-fw fa-diamond" aria-hidden="true"></i>&nbsp;&nbsp;Love</a></li><li><a href="https://cloud.mrbird.cn" target="_blank" itemprop="url" class="ignore-href"><i class="fa fa-fw fa-chain" aria-hidden="true"></i>&nbsp;&nbsp;FEBS</a></li><li><a href="/atom.xml" target="_blank" itemprop="url" class="ignore-href"><i class="fa fa-fw fa-rss" aria-hidden="true"></i>&nbsp;&nbsp;RSS</a></li><li><a href="https://gitee.com/mrbirdd" target="_blank" itemprop="sameAs" class="ignore-href"><i class="fa fa-fw fa-codepen" aria-hidden="true"></i>&nbsp;&nbsp;Gitee</a></li><li><a href="https://github.com/wuyouzhuguli" target="_blank" itemprop="sameAs" class="ignore-href"><i class="fa fa-fw fa-github-alt" aria-hidden="true"></i>&nbsp;&nbsp;GitHub</a></li><li><a href="javascript:;" class="popup-trigger"><i class="fa fa-fw fa-search" aria-hidden="true"></i>&nbsp;&nbsp;Search</a></li></ul></div></div></div><script>var $urls=$(".author__urls").find("a");$urls.each(function(){var o=$(this);o.mouseenter(function(){o.css({color:"#414547"})}),o.mouseleave(function(){o.css({color:""})})})</script></section><section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active"><div class="post-toc"><div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue入门"><span class="nav-number">1.</span> <span class="nav-text">Vue入门</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue组件"><span class="nav-number">2.</span> <span class="nav-text">Vue组件</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#全局Vue组件"><span class="nav-number">2.1.</span> <span class="nav-text">全局Vue组件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#局部Vue组件"><span class="nav-number">2.2.</span> <span class="nav-text">局部Vue组件</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue实例生命周期"><span class="nav-number">3.</span> <span class="nav-text">Vue实例生命周期</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#计算属性，方法和监听器"><span class="nav-number">4.</span> <span class="nav-text">计算属性，方法和监听器</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#计算属性"><span class="nav-number">4.1.</span> <span class="nav-text">计算属性</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#方法"><span class="nav-number">4.2.</span> <span class="nav-text">方法</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#监听器"><span class="nav-number">4.3.</span> <span class="nav-text">监听器</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#computed的getter和setter"><span class="nav-number">5.</span> <span class="nav-text">computed的getter和setter</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#深入理解Vue组件"><span class="nav-number">6.</span> <span class="nav-text">深入理解Vue组件</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#is"><span class="nav-number">6.1.</span> <span class="nav-text">is</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#子组件中的data应该为function"><span class="nav-number">6.2.</span> <span class="nav-text">子组件中的data应该为function</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#ref"><span class="nav-number">6.3.</span> <span class="nav-text">ref</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#父组件向子组件传值"><span class="nav-number">6.4.</span> <span class="nav-text">父组件向子组件传值</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#组件参数校验"><span class="nav-number">6.5.</span> <span class="nav-text">组件参数校验</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#给组件绑定原生事件"><span class="nav-number">6.6.</span> <span class="nav-text">给组件绑定原生事件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#非父子组件传值"><span class="nav-number">6.7.</span> <span class="nav-text">非父子组件传值</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#插槽slot"><span class="nav-number">6.8.</span> <span class="nav-text">插槽slot</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#作用域插槽"><span class="nav-number">6.9.</span> <span class="nav-text">作用域插槽</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#动态组件"><span class="nav-number">6.10.</span> <span class="nav-text">动态组件</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue动画特效"><span class="nav-number">7.</span> <span class="nav-text">Vue动画特效</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#构建第一个Vue项目"><span class="nav-number">8.</span> <span class="nav-text">构建第一个Vue项目</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#项目结构介绍"><span class="nav-number">9.</span> <span class="nav-text">项目结构介绍</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#单文件Vue组件"><span class="nav-number">9.1.</span> <span class="nav-text">单文件Vue组件</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Vue路由"><span class="nav-number">9.2.</span> <span class="nav-text">Vue路由</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#函数节流"><span class="nav-number">10.</span> <span class="nav-text">函数节流</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vuex实现数据共享"><span class="nav-number">11.</span> <span class="nav-text">Vuex实现数据共享</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vuex高级特性"><span class="nav-number">12.</span> <span class="nav-text">Vuex高级特性</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#Vuex-Getter"><span class="nav-number">12.1.</span> <span class="nav-text">Vuex Getter</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Vuex-Module"><span class="nav-number">12.2.</span> <span class="nav-text">Vuex Module</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#路由跳转"><span class="nav-number">13.</span> <span class="nav-text">路由跳转</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#路由参数传递"><span class="nav-number">14.</span> <span class="nav-text">路由参数传递</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#localStorage"><span class="nav-number">15.</span> <span class="nav-text">localStorage</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#keep-alive"><span class="nav-number">16.</span> <span class="nav-text">keep-alive</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#组件的递归"><span class="nav-number">17.</span> <span class="nav-text">组件的递归</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Vue项目打包上线"><span class="nav-number">18.</span> <span class="nav-text">Vue项目打包上线</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#异步组件加载"><span class="nav-number">19.</span> <span class="nav-text">异步组件加载</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#自定义Vue插件"><span class="nav-number">20.</span> <span class="nav-text">自定义Vue插件</span></a></li></ol></div></div></section></div></aside></div></main><footer id="footer" class="footer" onselectstart="return!1"><div class="footer-inner"><div class="copyright">&copy; 2016 - <span itemprop="copyrightYear">2019</span>&nbsp;&nbsp; <span class="author" itemprop="copyrightHolder">MrBird</span>&nbsp;&nbsp;|<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>&nbsp;&nbsp;UV&nbsp;<span class="busuanzi-value" id="busuanzi_value_site_uv" style="cursor:pointer" title="统计开始时间：2019年7月5日"></span> &nbsp;&nbsp;PV&nbsp;<span class="busuanzi-value" id="busuanzi_value_site_pv" style="cursor:pointer" title="统计开始时间：2019年7月5日"></span></div></div></footer><div class="back-to-top"><span style="font-family:'Source Sans Pro','Helvetica Neue',Arial,sans-serif;font-size:1.2em;font-weight:600">TOP</span></div></div><script type="text/javascript">"[object Function]"!==Object.prototype.toString.call(window.Promise)&&(window.Promise=null)</script><script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script><script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script><script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script><script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script><script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script><script type="text/javascript" src="/js/src/utils.js?v=5.1.1"></script><script type="text/javascript" src="/js/src/motion.js?v=5.1.1"></script><script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.1"></script><script type="text/javascript" src="/js/src/post-details.js?v=5.1.1"></script><script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.1"></script><script type="text/javascript">function proceedsearch(){$("body").append('<div class="search-popup-overlay local-search-pop-overlay"></div>').css("overflow","hidden"),$(".search-popup-overlay").click(onPopupClose),$(".popup").toggle();var t=$("#local-search-input");t.attr("autocapitalize","none"),t.attr("autocorrect","off"),t.focus()}var isfetched=!1,isXml=!0,search_path="search.xml";0===search_path.length?search_path="search.xml":search_path.endsWith("json")&&(isXml=!1);var path="/"+search_path,onPopupClose=function(t){$(".popup").hide(),$("#local-search-input").val(""),$(".search-result-list").remove(),$("#no-result").remove(),$(".local-search-pop-overlay").remove(),$("body").css("overflow","")},searchFunc=function(t,e,o){"use strict";$("body").append('<div class="search-popup-overlay local-search-pop-overlay"><div id="search-loading-icon"><i class="fa fa-spinner fa-pulse fa-2x fa-fw"></i></div></div>').css("overflow","hidden"),$("#search-loading-icon").css("margin","20% auto 0 auto").css("text-align","center"),$.ajax({url:t,dataType:isXml?"xml":"json",async:!0,success:function(t){isfetched=!0,$(".popup").detach().appendTo(".header-inner");var n=isXml?$("entry",t).map(function(){return{title:$("title",this).text(),content:$("content",this).text(),url:$("url",this).text()}}).get():t,r=document.getElementById(e),s=document.getElementById(o),a=function(){var t=r.value.trim().toLowerCase(),e=t.split(/[\s\-]+/);e.length>1&&e.push(t);var o=[];if(t.length>0&&n.forEach(function(n){function r(e,o,n,r){for(var s=r[r.length-1],a=s.position,i=s.word,l=[],h=0;a+i.length<=n&&0!=r.length;){i===t&&h++,l.push({position:a,length:i.length});var p=a+i.length;for(r.pop();0!=r.length&&(s=r[r.length-1],a=s.position,i=s.word,p>a);)r.pop()}return c+=h,{hits:l,start:o,end:n,searchTextCount:h}}function s(t,e){var o="",n=e.start;return e.hits.forEach(function(e){o+=t.substring(n,e.position);var r=e.position+e.length;o+='<b class="search-keyword">'+t.substring(e.position,r)+"</b>",n=r}),o+=t.substring(n,e.end)}var a=!1,i=0,c=0,l=n.title.trim(),h=l.toLowerCase(),p=n.content.trim().replace(/<[^>]+>/g,""),u=p.toLowerCase(),f=decodeURIComponent(n.url),d=[],g=[];if(""!=l&&(e.forEach(function(t){function e(t,e,o){var n=t.length;if(0===n)return[];var r=0,s=[],a=[];for(o||(e=e.toLowerCase(),t=t.toLowerCase());(s=e.indexOf(t,r))>-1;)a.push({position:s,word:t}),r=s+n;return a}d=d.concat(e(t,h,!1)),g=g.concat(e(t,u,!1))}),(d.length>0||g.length>0)&&(a=!0,i=d.length+g.length)),a){[d,g].forEach(function(t){t.sort(function(t,e){return e.position!==t.position?e.position-t.position:t.word.length-e.word.length})});var v=[];0!=d.length&&v.push(r(l,0,l.length,d));for(var C=[];0!=g.length;){var $=g[g.length-1],m=$.position,x=$.word,w=m-20,y=m+80;w<0&&(w=0),y<m+x.length&&(y=m+x.length),y>p.length&&(y=p.length),C.push(r(p,w,y,g))}C.sort(function(t,e){return t.searchTextCount!==e.searchTextCount?e.searchTextCount-t.searchTextCount:t.hits.length!==e.hits.length?e.hits.length-t.hits.length:t.start-e.start});var T=parseInt("1");T>=0&&(C=C.slice(0,T));var b="";b+=0!=v.length?"<li><a href='"+f+"' class='search-result-title'>"+s(l,v[0])+"</a>":"<li><a href='"+f+"' class='search-result-title'>"+l+"</a>",C.forEach(function(t){b+="<a href='"+f+'\'><p class="search-result">'+s(p,t)+"...</p></a>"}),b+="</li>",o.push({item:b,searchTextCount:c,hitCount:i,id:o.length})}}),1===e.length&&""===e[0])s.innerHTML='<div id="no-result"><i class="fa fa-search fa-5x" /></div>';else if(0===o.length)s.innerHTML='<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>';else{o.sort(function(t,e){return t.searchTextCount!==e.searchTextCount?e.searchTextCount-t.searchTextCount:t.hitCount!==e.hitCount?e.hitCount-t.hitCount:e.id-t.id});var a='<ul class="search-result-list">';o.forEach(function(t){a+=t.item}),a+="</ul>",s.innerHTML=a}};r.addEventListener("input",a),$(".local-search-pop-overlay").remove(),$("body").css("overflow",""),proceedsearch()}})};$(".popup-trigger").click(function(t){t.stopPropagation(),isfetched===!1?searchFunc(path,"local-search-input","local-search-result"):proceedsearch()}),$(".popup-btn-close").click(onPopupClose),$(".popup").click(function(t){t.stopPropagation()}),$(document).on("keyup",function(t){var e=27===t.which&&$(".search-popup").is(":visible");e&&onPopupClose()})</script></body><script>$(function(){$("a").not(".nav-link,.cloud-tie-join-count,.ignore-href,.jstree-anchor").addClass("animsition-link")});var burst1=new mojs.Burst({left:0,top:0,radius:{5:40},children:{shape:"circle",fill:["red","cyan","orange"],fillOpacity:.8,radiusX:3.5,radiusY:3.5}});document.addEventListener("click",function(a){null==a.target.href&&"footer"!=a.target.className&&"copyright"!=a.target.className&&"author__urls social-icons"!=a.target.className&&"author__avatar"!=a.target.className&&"sidebar sidebar-active"!=a.target.className&&burst1.tune({x:a.pageX,y:a.pageY}).generate().replay()})</script><script type="text/javascript" src="/js/message.js"></script></html><!-- rebuild by neat -->